package com.guomao.entity;

import com.guomao.functions.Hitable;
import com.guomao.functions.Recyclable;
import com.guomao.utils.CollisionUtils;
import com.guomao.utils.Direction;
import com.guomao.utils.Meta;
import com.guomao.utils.SoundUtils;

import java.io.IOException;
import java.lang.reflect.Member;
import java.util.Random;

public class EnemyTank extends Element implements Hitable, Recyclable {
    int num = 4;
    int surplus = 0;
    //游戏启动后坦克默认的指向
    Direction d = Direction.RIGHT;

    Direction unMoved;

    public EnemyTank(int x, int y) {
        super(x, y);
        super.path = "day16-javase-tank/images/enemy_1_r.gif";
        getSize();
        super.hp = 2;
    }

    public EnemyTank() {
    }

    //需要让move方法知道键盘按下的方向是哪里 ↓

    /**
     * 01-根据键盘指向移动坦克或者改变坦克方向
     *
     * @param d
     */
    public void move(Direction d) {
        if (unMoved != null && unMoved == d) {
            //在坦克移动的代码被中断之前 让坦克走完剩下留白距离
            switch (d) {
                case UP:
                    y -= surplus;
                    break;
                case DOWN:
                    y += surplus;
                    break;
                case LEFT:
                    x -= surplus;
                    break;
                case RIGHT:
                    x += surplus;
                    break;
            }
            return;
        }


        //如果传递进来的方向和当前坦克方向相同 纯粹的就是改变坐标
        if (d == this.d) {
            switch (d) {
                case UP:
                    this.y -= num;
                    break;

                case DOWN:
                    this.y += num;
                    break;

                case LEFT:
                    this.x -= num;
                    break;

                case RIGHT:
                    this.x += num;
                    break;
            }
        } else {
            //如果传递进来的方向和当前坦克方向不一致 那么需要先改变绘制的图片的方向 再修改坐标
            switch (d) {
                case UP:
                    this.path = "day16-javase-tank/images/enemy_1_u.gif";
                    break;

                case DOWN:
                    this.path = "day16-javase-tank/images/enemy_1_d.gif";
                    break;

                case LEFT:
                    this.path = "day16-javase-tank/images/enemy_1_l.gif";
                    break;

                case RIGHT:
                    this.path = "day16-javase-tank/images/enemy_1_r.gif";
                    break;
            }

            //记录当前坦克的真正指向
            this.d = d;
        }


        //如果向左移动x的坐标值变成负数说明越界 就把x的值修正为起点值0
        if (x < 0) {
            x = 0;
        }

        //如果向上移动y的坐标值变成负数说明越界 就把y的值修正为起点值0
        if (y < 0) {
            y = 0;
        }

        //如果向右移动x的坐标值大于屏幕宽度-坦克宽度 就把x的值修正为(屏幕宽度-坦克宽度)
        if (x > Meta.WIDTH - this.width) {
            x = Meta.WIDTH - this.width;
        }
        //如果向下移动y的坐标值大于屏幕高度-坦克高度 就把y的值修正为(屏幕高度-坦克高度)
        if (y > Meta.HEIGHT - this.height) {
            y = Meta.HEIGHT - this.height;
        }
    }


    /**
     * 02-坦克的开火方法 可以生成子弹
     * 该方法每被调用一次 就会生产一个子弹对象 应该加入时间间隔 创建子弹对象前 判断下时间有没有过去指定间隔 如果有就创建 否则不创建
     *
     * @return
     */


    long interval = 1000;
    long lastFireTime;

    /**
     * 02 每次开火发射子弹时先判断子弹发射时间间隔是否达到200ms
     *
     * @return
     */
    public Bullet fire() {
        Bullet bullet = null;
        //获取当前发射子弹的开火时间
        long currentFireTime = System.currentTimeMillis();
        //判断当前发射时间距离上一次开火时间是否达到了200ms
        if (currentFireTime - lastFireTime >= interval) {
            try {
                SoundUtils.play("day16-javase-tank/audio/fire.wav");
            } catch (IOException e) {
                e.printStackTrace();
            }
            bullet = new Bullet(x, y, width, height, d);
            //重新记录最后一次发射子弹的时间
            lastFireTime = currentFireTime;
        }
        return bullet;
    }


    /**
     * 03-判断坦克和墙体是否产生了碰撞
     *
     * @param e 要去进行碰撞判断的墙体对象
     * @return
     */
    public boolean isCollide(Element e) {
        //获取坦克的宽高坐标
        int x1 = this.x;
        int y1 = this.y;
        int w1 = this.width;
        int h1 = this.height;
        //第一种情况 是用坦克即时的坐标参数去和墙的坐标参数进行判断 如果墙体和坦克放生碰撞 坦克已经绘制完毕 事实上是嵌入在墙体中的状态
        //实际上 我们可以让坦克的坐标预加一些值 用加完之后的坐标值去和墙体进行比较

        switch (d) {
            case UP:
                y1 -= num;
                break;

            case DOWN:
                y1 += num;
                break;

            case LEFT:
                x1 -= num;
                break;

            case RIGHT:
                x1 += num;
                break;
        }

        //获取墙体的宽高坐标
        int x2 = e.x;
        int y2 = e.y;
        int w2 = e.width;
        int h2 = e.height;
        boolean flag = CollisionUtils.isCollisionWithRect(x1, y1, w1, h1, x2, y2, w2, h2);


        if (flag) {
            unMoved = d;
            //在坦克不能移动之后 计算出留白距离
            switch (d) {
                case UP:
                    surplus = super.y - y2 - h2;
                    break;
                case DOWN:
                    surplus = y2 - super.y - h1;
                    break;
                case LEFT:
                    surplus = super.x - x2 - w2;
                    break;
                case RIGHT:
                    surplus = x2 - super.x - w1;
                    break;
            }
        } else {
            unMoved = null;
        }

        return flag;
    }


    private final Random r = new Random();
    long e_interval = 2000;
    long e_lastRandomTime;

    @Override
    public void draw() {
        super.draw();
        //获取当前系统时间
        long currentRandomTime = System.currentTimeMillis();
        //判断此次时间-上一次生成随机数的时间是否满足间隔
        if (currentRandomTime - e_lastRandomTime >= e_interval) {
            int num = r.nextInt(4) + 1;
            switch (num) {
                case 1:
                    this.move(Direction.UP);
                    break;
                case 2:
                    this.move(Direction.DOWN);
                    break;
                case 3:
                    this.move(Direction.LEFT);
                    break;
                case 4:
                    this.move(Direction.RIGHT);
                    break;
            }
            e_lastRandomTime = currentRandomTime;
        } else {
            this.move(d);
        }
    }

    @Override
    public Blast showBlast() {
        hp--;
        return new Blast(x, y, width, height);
    }

    @Override
    public boolean isOutside() {
        return hp <= 0;
    }
}